﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using Nini.Config;

namespace ResponseMonitor
{
    public class EprimeParser
    {
        private string _fileContent = string.Empty;
        private IConfigSource _nini = null;
        private string _procName = string.Empty;
        private ESData _esdata = new ESData();
        private MSCData _mscdata = new MSCData();
        private int _internalError = -1;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="filePath">eprime文件路径</param>
        public EprimeParser(string filePath, string procName)
        {
            if (!File.Exists(filePath))
            {
                // todo: 记录错误日志
                throw new Exception("e-prime file is not exist.");
            }
            else
            {
                try
                {
                    using (StreamReader sr = new StreamReader(filePath, Encoding.Default))
                    {
                        _fileContent = sr.ReadToEnd();
                    }
                    this._procName = procName;

                    string ini = _fileContent.Split(new string[] { "\r\n\r\n" }, 2, StringSplitOptions.RemoveEmptyEntries)[1];
                    byte[] bs = System.Text.Encoding.Default.GetBytes(ini);
                    MemoryStream ms = new MemoryStream(bs);

                    _nini = new IniConfigSource(ms);
                }
                catch (Exception ex)
                {
                    // todo: 记录错误日志
                    throw new Exception("There are errors on reading e-prime file.", ex);
                }
            }

            _process();
        }

        /// <summary>
        /// 生成供ResponseMonitor使用的msc文件数据结构
        /// </summary>
        /// <returns>msc文件数据结构</returns>
        public string GenerateMSCData()
        {
            if (_internalError != 0) // 如果不为0说明处理过程中发生错误
                return null;

            string result = string.Empty;
            result += (string.Format("buffer={0}", _mscdata.Items[0].StimTime) + "\r\n");
            
            int t = _mscdata.PrepareTime;
            foreach (Item i in _mscdata.Items)
            {
                result += (string.Format("{0}:{1}", t, i.Answer) + "\r\n");
                t += i.StimTime + i.StimPrepare;
            }

            return result;
        }

        /// <summary>
        /// 初步解析文件, 判断文件是简单文件还是复杂文件, 然后分别调用不同的方法进行解析
        /// 判断标准:
        ///   判断主流程中第一个List的第一个自定义参数列名称是否为"stim".
        ///   如果是, 则认为是简单文件; 否则, 认为是复杂文件
        /// </summary>
        private void _process()
        {
            bool isCorrectFile = false;
            int mainProcItemsCount = int.Parse(_getStringByName(_procName, "FlowLines(0).Count"));
            for (int i = 0; i < mainProcItemsCount; i++)
            {
                string flowItemName = _getStringByName(_procName, string.Format("FlowLines(0).FlowItem({0}).Name", i));
                string flowItemType = _getStringByName(flowItemName, "TypeName");
                if (flowItemType.ToLower() == "list")
                {
                    isCorrectFile = true;
                    string attrName1 = _getStringByName(flowItemName, "Attributes(1).Name");
                    if (attrName1.ToLower() == "stim")
                        _processSimple();
                    else
                        _processComplex();
                }
            }
            if (isCorrectFile)
                _internalError ++;
        }

        /// <summary>
        /// 用nini解析简单文件
        /// </summary>
        private void _processSimple()
        {
            string prepareContainerName = _getStringByName(_procName, "FlowLines(0).FlowItem(0).Name");
            string listName = _getStringByName(_procName, "FlowLines(0).FlowItem(1).Name");

            //  取得prepare
            string prepare = _getStringByName(prepareContainerName, "Duration");
            _mscdata.PrepareTime = int.Parse(prepare);

            //  
            int levels = int.Parse(_getStringByName(listName, "Levels"));
            for (int i = 1; i <= levels; i++)
            {
                // 取得各个stim和answer
                string k = string.Format("Levels({0}).ValueString", i);
                string v = _getStringByName(listName, k);
                string [] vs = v.Split(new string [] {@"\t"}, StringSplitOptions.RemoveEmptyEntries);
                string procName = vs[1];
                string stim = vs[2];
                string answer = vs[3];

                // 取得各个durition
                string stimTimeName = _getStringByName(procName, "FlowLines(0).FlowItem(0).Name");
                string stimPrepareName = _getStringByName(procName, "FlowLines(0).FlowItem(1).Name");
                string stimTime = _getStringByName(stimTimeName, "Duration");
                string stimPrepare = _getStringByName(stimPrepareName, "Duration");

                _mscdata.Items.Add(new Item(stim, answer, int.Parse(stimTime), int.Parse(stimPrepare)));
            }
        }

        private void _processComplex()
        {
            int mainProcItemsCount = int.Parse(_getStringByName(_procName, "FlowLines(0).Count"));
            for (int i = 0; i < mainProcItemsCount; i++)
            {
                string flowItemName = _getStringByName(_procName, string.Format("FlowLines(0).FlowItem({0}).Name", i));
                string flowItemType = _getStringByName(flowItemName, "TypeName");
                if (flowItemType.ToLower() == "list")
                {
                    int levelsCount = int.Parse(_getStringByName(flowItemName, "Levels"));
                    string subProcName = _getStringByName(flowItemName, "Attributes(\"Procedure\").DefaultValue");
                    string attrName1 = _getStringByName(flowItemName, "Attributes(1).Name");

                    //
                    int subProcItemCount = int.Parse(_getStringByName(subProcName, "FlowLines(0).Count"));
                    int preDuration = 0;
                    int postDuration = 0;
                    bool preFlag = true;
                    string finalListName = string.Empty;
                    for (int j = 0; j < subProcItemCount; j++)
                    {
                        string subFlowItemName = _getStringByName(subProcName, string.Format("FlowLines(0).FlowItem({0}).Name", j));
                        string subFlowItemType = _getStringByName(subFlowItemName, "TypeName");
                        if (subFlowItemType.ToLower() == "list")
                        {
                            finalListName = subFlowItemName;
                            preFlag = false;
                            continue;
                        }
                        int duration = int.Parse(_getStringByName(subFlowItemName, "Duration"));
                        if (duration == -1) duration = 0;
                        if (preFlag)
                            preDuration += duration;
                        else
                            postDuration += duration;
                    }

                    //
                    if (_mscdata.PrepareTime == -1)
                        _mscdata.PrepareTime = preDuration;
                    else
                        _mscdata.PrepareTime += preDuration;

                    //
                    string finalProcName = _getStringByName(finalListName, "Attributes(\"Procedure\").DefaultValue");
                    int finalProcItemCount = int.Parse(_getStringByName(finalProcName, "FlowLines(0).Count"));
                    int finalLevelsCount = int.Parse(_getStringByName(finalListName, "Levels"));

                    if (finalProcItemCount != 2)
                    {
                        _internalError = 1;
                        return;
                    }

                    int stimTime = int.Parse(_getStringByName(_getStringByName(finalProcName, "FlowLines(0).FlowItem(0).Name"), "Duration"));
                    int stimPrepare = int.Parse(_getStringByName(_getStringByName(finalProcName, "FlowLines(0).FlowItem(1).Name"), "Duration"));

                    for (int j = 0; j < levelsCount; j++)
                    {
                        if (attrName1.ToLower() == "stimlist")   // 判断主流程中第一个List的第一个自定义参数列名称是否为"stim".
                        {
                            string v = _getStringByName(flowItemName, string.Format("Levels({0}).ValueString", j+1));
                            string[] vs = v.Split(new string[] { @"\t" }, StringSplitOptions.RemoveEmptyEntries);
                            string refName = vs[vs.Length - 1];
                            for (int k = 0; k < finalLevelsCount; k++)
                            {
                                string vv = _getStringByName(refName, string.Format("Levels({0}).ValueString", k+1));
                                string[] vvs = vv.Split(new string[] { @"\t" }, StringSplitOptions.RemoveEmptyEntries);
                                string stim = vvs[vvs.Length - 2];
                                string answer = vvs[vvs.Length - 1];
                                _mscdata.Items.Add(new Item(stim, answer, stimTime, stimPrepare));
                            }
                            _mscdata.Items[_mscdata.Items.Count - 1].StimPrepare += (postDuration + preDuration);
                        }
                        else
                        {
                            for (int k = 0; k < finalLevelsCount; k++)
                            {
                                // 取得各个stim和answer
                                string v = _getStringByName(finalListName, string.Format("Levels({0}).ValueString", k+1));
                                string[] vs = v.Split(new string[] { @"\t" }, StringSplitOptions.RemoveEmptyEntries);
                                string stim = vs[vs.Length - 2];
                                string answer = vs[vs.Length - 1];
                                _mscdata.Items.Add(new Item(stim, answer, stimTime, stimPrepare));
                            }
                            _mscdata.Items[_mscdata.Items.Count - 1].StimPrepare += (postDuration + preDuration);
                        }
                    }

                    break;
                }
                else if (flowItemType.ToLower() == "textdisplay")
                {
                    int prepareTime = int.Parse(_getStringByName(flowItemName, "Duration"));
                    if (prepareTime == -1)
                        prepareTime = 0;

                    if (_mscdata.PrepareTime == -1)
                        _mscdata.PrepareTime = prepareTime;
                    else
                        _mscdata.PrepareTime += prepareTime;
                }
            }
        }

        private string _getStringByName(string name, string key)
        {
            return _getUnknowValueByKnown("Name", name, key);
        }

        private string _getUnknowValueByKnown(string knowKey, string knowValue, string unknowKey)
        {
            foreach (IConfig ic in _nini.Configs)
            {
                string n = ic.Get(knowKey);
                if (n == knowValue)
                {
                    string r = ic.Get(unknowKey);
                    if (r != null)
                        return r;
                    else
                        return null;
                }
            }
            return null;
        }

        public MSCData MSCData
        {
            get { return _mscdata; }
        }
    }
}
